using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Data.SqlClient;
using Microsoft.SqlServer.Management.Smo;
using System.Data;
using Microsoft.ApplicationBlocks.Data;
using System.Text.RegularExpressions;

namespace Microsoft.SharedSource.SqlServer.MDDE.Extensions
{
    public abstract class TemplateInstanceCreator
    {
        protected string connectionString;
        // Tablename and a list of mandatory columns.
        protected Dictionary<string,string[]> tableInfo;
        // Query to get the instance names.
        protected string getInstancesQuery;

        public string ConnectionString
        {
            get
            {
                return this.connectionString;
            }
            set
            {
                // Do not use SqlConnectionStringBuilder here.
                // It doesn't support some of the keywords.
                Regex dotFinder = new Regex("(Data Source=\\.)(.*)");

                this.connectionString =
                    dotFinder.Replace(value, 
                    "Data Source=" + System.Environment.MachineName + "$2");
            }
        }

        public virtual bool ValidateInstanceRepository()
        {
            // See if we can connect to the repository.
            try
            {
                // Do not use SqlConnectionStringBuilder here.
                // It doesn't support some of the keywords.
                Regex serverFinder = new Regex("Data Source=([^;]*).*");
                string serverName = 
                    serverFinder.Replace(ConnectionString, "$1");

                // Get the server.
                Server server = new Server(serverName);

                // Get the database.
                Regex initCatFinder = 
                    new Regex("(.*)Initial Catalog=([^;]*).*");
                string dbName =
                    initCatFinder.Replace(ConnectionString, "$2");

                Database etlMeta = server.Databases[dbName];

                // See if the repository contains validation tables.
                foreach (KeyValuePair<string,string[]> kvp in tableInfo)
                {
                    // Check for the existence of table.
                    string tableName = kvp.Key;

                    if (!etlMeta.Tables.Contains(tableName))
                        return false;

                    Table objTable = etlMeta.Tables[tableName];

                    // Get the columns.
                    foreach (string columnName in kvp.Value)
                    {
                        // Check for column existence.
                        if (!objTable.Columns.Contains(columnName))
                            return false;
                    }
                }
                return true;
            }
            catch
            {
                return false;
            }
        }

        public virtual List<string> GetInstanceList()
        {
            List<string> instances = new List<string>();

            try
            {
                // Get the instance names.
                DataSet ds =
                    SqlHelper.ExecuteDataset(
                    connectionString,
                    CommandType.Text,
                    getInstancesQuery);

                foreach (DataRow r in ds.Tables[0].Rows)
                    instances.Add(r["TableName"].ToString());
            }
            catch
            {
                // Gobble up all exceptions.
            }

            return instances;
        }

        public virtual XmlDocument GetInstanceConfigurationData(
            string instanceName)
        {
            return null;
        }


        #region Helper Methods

        protected void AppendMapping(
            XmlDocument configData, XmlElement configElement,
            string sourceColumn, string usage, string destinationColumn)
        {
            XmlElement mappingElement =
                configData.CreateElement("Mapping");
            configElement.AppendChild(mappingElement);

            XmlAttribute attrib =
                configData.CreateAttribute("SourceColumnName");
            attrib.Value = sourceColumn;
            mappingElement.Attributes.Append(attrib);

            attrib =
                configData.CreateAttribute("SourceColumnUsage");
            attrib.Value = usage;
            mappingElement.Attributes.Append(attrib);

            attrib =
            configData.CreateAttribute("DestinationColumnName");
            attrib.Value = destinationColumn;
            mappingElement.Attributes.Append(attrib);
        }

        protected XmlElement AppendColumn(
            XmlDocument configData, XmlElement collectionElement,
            string columnName)
        {
            XmlElement column =
                configData.CreateElement("Column");
            collectionElement.AppendChild(column);

            XmlAttribute attrib =
                configData.CreateAttribute("Name");
            attrib.Value = columnName;
            column.Attributes.Append(attrib);

            return column;
        }

        protected XmlElement AppendColumnCollection(
            XmlDocument configData, XmlElement configElement,
            string collectionType, string collectionName)
        {
            XmlElement collection =
                configData.CreateElement("ColumnCollection");
            configElement.AppendChild(collection);

            XmlAttribute attrib =
                configData.CreateAttribute("Type");
            attrib.Value = collectionType;
            collection.Attributes.Append(attrib);

            attrib =
                configData.CreateAttribute("Name");
            attrib.Value = collectionName;
            collection.Attributes.Append(attrib);

            return collection;
        }

        protected void AppendConfigurableProperty(
            XmlDocument configData, XmlElement configElement,
             string propertyName, string propertyValue)
        {
            XmlElement property =
                configData.CreateElement("ConfigurableProperty");
            configElement.AppendChild(property);

            XmlAttribute attrib =
                configData.CreateAttribute("Name");
            attrib.Value = propertyName;
            property.Attributes.Append(attrib);

            attrib =
                configData.CreateAttribute("Value");
            attrib.Value = propertyValue;
            property.Attributes.Append(attrib);
        }

        protected XmlElement AppendConfigurableComponent(
            XmlDocument configData, XmlElement root, string componentUri)
        {
            XmlElement component =
                configData.CreateElement("ConfigurableComponent");
            root.AppendChild(component);

            XmlAttribute uri =
                configData.CreateAttribute("ComponentUri");
            component.Attributes.Append(uri);
            uri.Value = componentUri;

            return component;
        }

        #endregion

    }
}
